/**
 * @brief 进行事件监控管理的模块
 * @brief
 * 1.事件循环开始后,从poll中的epoll_wait返回，得到所有描述符对应的channel,然后调用对应channel的handleEvent进行对应的读写事件处理
 * 处理完所有描述符的事件之后,执行任务队列中的任务(用户自己创建线程,导致不是对应的线程处理的,因而加入到了任务队列)
 * 2.为了防止一直没有事件进行返回,而其他线程将任务加入到了任务队列而一直阻塞,导致任务队列中的任务一直得不到执行,所有就添加了一个event_fd
 * 和对应的channel,开始时启动对应的读事件监控,有任务压入任务队列的时候,就向eventfd中写入数据,使epoll_wait能够进行返回,从而执行任务队列中的任务
 * 3.定时器事件作为任务加入到任务队列中进行执行
 */
#pragma once

#include <vector>
#include <functional>
#include <thread>
#include <mutex>
#include <sys/eventfd.h>

#include "logger.hpp"
#include "poller.hpp"
#include "timerWheel.hpp"

namespace hdp
{
    // 事件循环
    class EventLoop
    {
    private:
        using Functor = std::function<void()>;
        std::thread::id _thread_id;              // 线程ID
        int _event_fd;                           // eventfd唤醒IO事件监控有可能导致的阻塞
        std::unique_ptr<Channel> _event_channel; // eventfd对应的channel
        Poller _poller;                          // 进行描述符的事件监控
        std::vector<Functor> _tasks;             // 任务池
        std::mutex _mutex;                       // 实现任务池操作的线程安全
        TimerWheel _timer_wheel;                 // 定时器模块
    private:
        // 执行任务池中的所有任务
        void RunAllTask()
        {
            std::vector<Functor> functor;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _tasks.swap(functor);
            }

            for (auto &func : functor)
            {
                func();
            }
            return;
        }

        // 创建一个eventfd对象,实现事件通知
        static int CreateEventFd()
        {
            // int eventfd(unsigned int initval, int flags);
            // EFD_CLOEXEC--禁止进程复制
            // EFD_NONBLCK--启动非阻塞属性
            int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
            if (efd < 0)
            {
                LOG_ERROR("eventfd create failed");
                abort();
            }
            return efd;
        }

        // 读取eventfd中的数据,来完成清0-线程接收通知
        void ReadEventFd()
        {
            uint64_t res = 0;
            int ret = read(_event_fd, &res, sizeof(res));
            if (ret <= 0)
            {
                // EINTR----被信号打断  EAGAIN -- 表示无数据可读
                if (errno == EINTR || errno == EAGAIN)
                {
                    return;
                }
                LOG_ERROR("read eventfd failed");
                abort();
            }
            return;
        }

        // 向eventfd写入数据，实现线程的通知
        void WeakUpEventFd()
        {
            uint64_t val = 1;
            int ret = write(_event_fd, &val, sizeof(val));
            if (ret < 0)
            {
                if (errno == EINTR)
                {
                    return;
                }
                LOG_ERROR("write eventfd failed");
                abort();
            }
            return;
        }

    public:
        EventLoop() : _thread_id(std::this_thread::get_id()),
                      _event_fd(CreateEventFd()),
                      _event_channel(new Channel(this, _event_fd)),
                      _timer_wheel(this)
        {
            // 给eventfd 添加可读事件回调函数,读取eventfd事件通知次数
            _event_channel->SetReadCallback(std::bind(&EventLoop::ReadEventFd, this));
            // 启动eventfd的读事件监控
            _event_channel->EnableRead();
        }

        // 三步走---事件监控--》就绪事件处理--》执行任务
        void Start()
        {
            for (;;)
            {
                // 1.事件监控
                std::vector<Channel *> actives;
                _poller.Poll(&actives);

                // 2.就绪事件处理
                for (auto &channel : actives)
                {
                    channel->HandleEvent();
                }
                // 3.执行任务
                RunAllTask();
            }
        }

        // 用于判断当前线程是否是EventLoop对应的线程
        bool IsInLoop()
        {
            return _thread_id == std::this_thread::get_id();
        }

        void AssertInLoop()
        {
            assert(_thread_id == std::this_thread::get_id());
        }

        // 判断将要执行的任务是否处于当前线程中
        void RunInLoop(const Functor &cb)
        {
            if (IsInLoop())
            {
                return cb();
            }
            return QueueInLoop(cb);
        }

        // 将操作压入任务池
        void QueueInLoop(const Functor &cb)
        {
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _tasks.push_back(cb);
            }
            // 唤醒有可能因为没有事件就绪,而导致的epoll阻塞
            // 其实就是给eventfd写入一个数据,eventfd就会触发可读事件
            WeakUpEventFd();
        }

        // 添加/修改描述符的事件监控
        void UpdateEvent(Channel *channel)
        {
            return _poller.UpdateEvent(channel);
        }

        // 移除描述符的事件监控
        void RemoveEvent(Channel *channel)
        {
            return _poller.RemoveEvent(channel);
        }

        // 添加定时任务
        void TimerAdd(const uint64_t &id, const uint32_t &delay, const TaskFunc &cb)
        {
            return _timer_wheel.TimerAdd(id, delay, cb);
        }

        // 刷新定时任务
        void TimerRefresh(const uint64_t &id)
        {
            return _timer_wheel.TimerRefresh(id);
        }

        // 取消定时任务
        void TimerCancel(const uint64_t &id)
        {
            return _timer_wheel.TimerCancel(id);
        }

        bool HasTimer(const uint64_t &id)
        {
            return _timer_wheel.HasTimer(id);
        }
    };

    // 移除监控
    void Channel::Remove() { return _loop->RemoveEvent(this); }
    // 添加监控
    void Channel::Update() { return _loop->UpdateEvent(this); }

    void TimerWheel::TimerAdd(const uint64_t &id, const uint32_t &delay, const TaskFunc &cb)
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, delay, cb));
    }
    // 刷新/延迟定时任务
    void TimerWheel::TimerRefresh(const uint64_t &id)
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
    }
    void TimerWheel::TimerCancel(const uint64_t &id)
    {
        _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
    }
}